/*
  Name: DeadProxyNetworkHandler.cpp
  Copyright:
  Author: Carl Chatfield
  Date: 20/01/08 13:28
  Description: Manages network events for each client
*/
#include "DeadProxyClientNetworkHandler.h"
#include "DeadProxyClient.h"
#include "DeadProxyApp.h"

FILE * logfile;

ClientNetworkHandler::ClientNetworkHandler(void* ptrClient)
{
    ToClientBufferSend = 0;
    ToServerBufferSend = 0;
    ToClientBufferRecv = 0;
    ToServerBufferRecv = 0;
    ToClientCanSend = false;
    ToServerCanSend = false;
    ToClientPacketQueue = new PacketQueue;
    ToServerPacketQueue = new PacketQueue;
    pClient = ptrClient;
}

ClientNetworkHandler::~ClientNetworkHandler()
{
    if(ToClientBufferSend != 0)
    {
        delete ToClientBufferSend;
    }
    if(ToClientBufferRecv != 0)
    {
        delete ToClientBufferRecv;
    }
    if(ToServerBufferSend != 0)
    {
        delete ToServerBufferSend;
    }
    if(ToServerBufferRecv != 0)
    {
        delete ToServerBufferRecv;
    }
    delete ToClientPacketQueue;
    delete ToServerPacketQueue;
}

int ClientNetworkHandler::OnAccept(ClientEvent * evt)
{
    ToClientSocket = (SOCKET)evt->GetParam3();
    ToServerSocket = (SOCKET)evt->GetParam4();
    ToClientPacketQueue->Clear();
    ToServerPacketQueue->Clear();
    LoginOrGame = evt->GetParam1();
    ToClientCanSend = false;
    ToServerCanSend = false;
    return 0;
}

int ClientNetworkHandler::OnConnect(ClientEvent * evt)
{
    ((Client*)pClient)->GetKey();
    return 0;
}

int ClientNetworkHandler::OnRead(ClientEvent * evt)
{
    unsigned int wParam = (unsigned int)evt->GetParam1();
    unsigned short PacketLen;
    ClientEvent * sendevt;
    int res = 0;
    int ReadLen = 0;
    int offset = 0;
    if(wParam == ToClientSocket)
    {
        //Read Some Data
        res = recv(ToClientSocket, (char*)ToClientRawBuffer, 65536, 0);
        if(res == SOCKET_ERROR)
        {
            if(WSAGetLastError() == WSAEWOULDBLOCK) //if the buffer is full
            {
                return 0; //then break
            } else {
                return 0; //for now just break on any error
            }
        }
        while(true) //We dont know how many packets we read, so we have to loop until we reach the end of the buffer
        {
            if(ToClientBufferRecv == 0)
            {
                ToClientBufferRecv = new PacketBuffer();
                memcpy(&PacketLen, (char*)(ToClientRawBuffer + offset), 2); //read the pack len
                ToClientBufferRecv->NewBuffer(PacketLen + 2); //allocate pack len bytes + 2 for the packlen
            }
            if((res - offset) > ToClientBufferRecv->GetLength() - ToClientBufferRecv->GetPos())
            {
                ReadLen = ToClientBufferRecv->GetLength() - ToClientBufferRecv->GetPos();
            } else {
                ReadLen = res - offset;
            }
            ToClientBufferRecv->WriteCharArray((unsigned char *)(ToClientRawBuffer + offset), ReadLen);
            offset = offset + ReadLen; //add the data taken from the buffer to offset
            if(ToClientBufferRecv->GetLength() == ToClientBufferRecv->GetPos()) //Check if we have reached the end of the packet
            {
                ToClientBufferRecv->SetPos(0); //Set pos back to 0
                sendevt = new ClientEvent(CE_PACKET); //it is a packet event
                sendevt->SetParam1(0); //it is being sent
                sendevt->SetParam2(LoginOrGame); //is it a login packet or game packet
                sendevt->SetParam3((int)ToClientBufferRecv); //send the ptr to the packet
                ((Client*)pClient)->PostEvent(sendevt); //post off the packet
                ToClientBufferRecv = 0; //set it to 0 so it will be renewed next loop
            }
            if(offset >= res) //if we have reached the end of the data
            {
                break;
            }
        }
    }
    if(wParam == ToServerSocket)
    {
        //Read Some Data
        res = recv(ToServerSocket, (char*)ToServerRawBuffer, 65536, 0);
        if(res == SOCKET_ERROR)
        {
            if(WSAGetLastError() == WSAEWOULDBLOCK) //if the buffer is full
            {
                return 0; //then break
            } else {
                return 0; //for now just break on any error
            }
        }
        while(true) //We dont know how many packets we read, so we have to loop until we reach the end of the buffer
        {
            if(ToServerBufferRecv == 0)
            {
                ToServerBufferRecv = new PacketBuffer();
                memcpy(&PacketLen, (char*)(ToServerRawBuffer + offset), 2);       //read the pack len
                ToServerBufferRecv->NewBuffer(PacketLen + 2);   //allocate pack len bytes + 2 for the packlen
            }
            if((res - offset) > ToServerBufferRecv->GetLength() - ToServerBufferRecv->GetPos())
            {
                ReadLen = ToServerBufferRecv->GetLength() - ToServerBufferRecv->GetPos();
            } else {
                ReadLen = res - offset;
            }
            ToServerBufferRecv->WriteCharArray((unsigned char *)(ToServerRawBuffer + offset), ReadLen);
            offset = offset + ReadLen; //add the data taken from the buffer to offset
            if(ToServerBufferRecv->GetLength() == ToServerBufferRecv->GetPos())     //Check if we have reached the end of the packet
            {
                ToServerBufferRecv->SetPos(0); //Set pos back to 0
                sendevt = new ClientEvent(CE_PACKET); //it is a packet event
                sendevt->SetParam1(1); //it is being recvd
                sendevt->SetParam2(LoginOrGame); //is it a login packet or game packet
                sendevt->SetParam3((int)ToServerBufferRecv); //send the ptr to the packet
                ((Client*)pClient)->PostEvent(sendevt); //post off the packet
                ToServerBufferRecv = 0; //set it to 0 so it will be renewed next loop
            }
            if(offset >= res) //if we have reached the end of the data
            {
                break;
            }
        }
    }
    return 0;
}

int ClientNetworkHandler::OnWrite(ClientEvent * evt)
{
    unsigned int wParam = (unsigned int)evt->GetParam1();
    if(wParam == ToClientSocket)
    {
        ToClientCanSend = true;
        WriteToSocket(ToClientSocket);
    }
    if(wParam == ToServerSocket)
    {
        ToServerCanSend = true;
        WriteToSocket(ToServerSocket);
    }
    return 0;
}

int ClientNetworkHandler::OnClose(ClientEvent * evt)
{
    unsigned int wParam = (unsigned int)evt->GetParam1();
    if(wParam == ToClientSocket)
    {
        shutdown(ToServerSocket, SD_BOTH); //if one socket closes, we have to shut down the other
        closesocket(ToClientSocket); //close the disconnected socket
    }
    if(wParam == ToServerSocket)
    {
        shutdown(ToClientSocket, SD_RECEIVE); //if one socket closes, we have to shut down the other
        WriteToSocket(ToClientSocket); //Send any data still queued to the client. If this happens to the server we dont care
        closesocket(ToServerSocket); //close the disconnected socket
    }
    return 0;
}

void ClientNetworkHandler::Message(ClientEvent * evt)
{
    int lParam = evt->GetParam2();
    switch (WSAGETSELECTEVENT(lParam))
    {
        case FD_ACCEPT:
            OnAccept(evt);
            break;
        case FD_CONNECT:
            OnConnect(evt);
            break;
        case FD_READ:
            OnRead(evt);
            break;
        case FD_WRITE:
            OnWrite(evt);
            break;
        case FD_CLOSE:
            OnClose(evt);
            break;
    }
}

void ClientNetworkHandler::SendToServer(PacketBuffer * packet)
{
    packet->SetPos(0);
    ToClientPacketQueue->AddPacket(packet);
    if(ToClientCanSend)
    {
        WriteToSocket(ToServerSocket);
    }
}

void ClientNetworkHandler::SendToClient(PacketBuffer * packet)
{
    packet->SetPos(0);
    ToServerPacketQueue->AddPacket(packet);
    if(ToServerCanSend)
    {
        WriteToSocket(ToClientSocket);
    }
}

void ClientNetworkHandler::WriteToSocket(SOCKET s)
{
    int res;
    if(s == ToClientSocket)
    {
        if(ToClientBufferSend == 0)
        {
            ToClientBufferSend = ToServerPacketQueue->GetPacket();
            if(ToClientBufferSend == 0)
            {
                return; //There are no more packets, so return
            }
        }
        while(true)
        {
            res = send(ToClientSocket,
                       (char*)(ToClientBufferSend->GetBuffer() + ToClientBufferSend->GetPos()), //Data at buffer + pos
                       ToClientBufferSend->GetLength() - ToClientBufferSend->GetPos(), //Max we can write is length - pos
                       0);
            if(res == SOCKET_ERROR)
            {
                if(WSAGetLastError() == WSAEWOULDBLOCK) //if the buffer is full
                {
                    ToServerCanSend = false;
                    break; //then break
                } else {
                    break; //for now just break on any error
                }
            }
            ToClientBufferSend->Skip(res);
            if(ToClientBufferSend->GetLength() == ToClientBufferSend->GetPos()) //if we finish writing our data
            {
                delete ToClientBufferSend;
                ToClientBufferSend = ToServerPacketQueue->GetPacket(); //Get Next Packet
                if(ToClientBufferSend == 0)
                {
                    return; //There are no more packets, so return
                }
            }
        }
    }
    if(s == ToServerSocket)
    {
        if(ToServerBufferSend == 0)
        {
            ToServerBufferSend = ToClientPacketQueue->GetPacket();
            if(ToServerBufferSend == 0)
            {
                return; //There are no more packets, so return
            }
        }
        while(true)
        {
            res = send(ToServerSocket,
                       (char*)(ToServerBufferSend->GetBuffer() + ToServerBufferSend->GetPos()), //Data at buffer + pos
                       ToServerBufferSend->GetLength() - ToServerBufferSend->GetPos(), //Max we can write is length - pos
                       0);
            if(res == SOCKET_ERROR)
            {
                if(WSAGetLastError() == WSAEWOULDBLOCK) //if the buffer is full
                {
                    ToClientCanSend = false;
                    break; //then break
                } else {
                    break; //for now just break on any error
                }
            }
            ToServerBufferSend->Skip(res);
            if(ToServerBufferSend->GetLength() == ToServerBufferSend->GetPos()) //if we finish writing our data
            {
                delete ToServerBufferSend;
                ToServerBufferSend = ToClientPacketQueue->GetPacket(); //Get Next Packet
                if(ToServerBufferSend == 0)
                {
                    return; //There are no more packets, so return
                }
            }
        }
    }
}
